#include <errno.h>
#include <stdarg.h>
#include <string.h>

#include "data_codec.h"

// 全局变量
static log_level_t current_log_level = LOG_INFO;
static log_fn_t current_log_fn = NULL;
static uint8_t buffer[MAX_PACKET_SIZE]; // 使用宏定义的静态缓冲区

// 日志消息函数
static void log_message(log_level_t level, const char *format, ...)
{
    if (level <= current_log_level && current_log_fn)
    {
        va_list args;
        va_start(args, format);
        current_log_fn(level, format, args);
        va_end(args);
    }
}

// 计算校验和
static uint16_t calculate_crc(const uint8_t *data, size_t length)
{
    uint16_t crc = 0;
    for (size_t i = 0; i < length; ++i)
    {
        if (i != offsetof(pkt_t, crc) && i != offsetof(pkt_t, crc) + 1)
        {
            crc += data[i];
        }
    }
    return crc;
}

// 编码函数
static void encode_packet(const pkt_t *packet, const uint8_t *data, uint8_t *buffer, size_t *len)
{
    if (packet->len > MAX_PACKET_SIZE)
    {
        log_message(LOG_ERROR, "Packet size exceeds MAX_PACKET_SIZE");
        return;
    }
    size_t header_size = offsetof(pkt_t, data);
    memcpy(buffer, packet, header_size);
    memcpy(buffer + header_size, data, packet->data_len);
    uint16_t crc = calculate_crc(buffer, packet->len);
    memcpy(buffer + offsetof(pkt_t, crc), &crc, sizeof(crc));
    *len = packet->len;
}

// 解码函数
static int decode_stream(const uint8_t *stream, size_t stream_len, pkt_t *packet)
{
    static enum
    {
        WAIT_FOR_HEADER,
        READ_LENGTH,
        READ_PAYLOAD
    } state = WAIT_FOR_HEADER;
    static size_t buffer_pos = 0;
    const uint16_t sync_word = HEADER_SYNC;

    for (size_t i = 0; i < stream_len; ++i)
    {
        uint8_t byte = stream[i];
        switch (state)
        {
            case WAIT_FOR_HEADER:
                if (buffer_pos < sizeof(buffer))
                {
                    buffer[buffer_pos++] = byte;
                }
                if (buffer_pos == 2 && memcmp(buffer, &sync_word, 2) == 0)
                {
                    state = READ_LENGTH;
                }
                else if (buffer_pos >= 2)
                {
                    buffer_pos = 0;
                }
                break;
            case READ_LENGTH:
                if (buffer_pos < sizeof(buffer))
                {
                    buffer[buffer_pos++] = byte;
                }
                if (buffer_pos == 4)
                {
                    uint16_t len;
                    memcpy(&len, buffer + 2, sizeof(len));
                    if (len <= MAX_PACKET_SIZE)
                    {
                        state = READ_PAYLOAD;
                    }
                    else
                    {
                        log_message(LOG_ERROR, "Packet size exceeds MAX_PACKET_SIZE");
                        buffer_pos = 0;
                        state = WAIT_FOR_HEADER;
                    }
                }
                break;
            case READ_PAYLOAD:
                if (buffer_pos < sizeof(buffer))
                {
                    buffer[buffer_pos++] = byte;
                }
                if (buffer_pos == ((pkt_t *)buffer)->len)
                {
                    uint16_t crc = calculate_crc(buffer, buffer_pos);
                    uint16_t packet_crc;
                    memcpy(&packet_crc, buffer + offsetof(pkt_t, crc), sizeof(packet_crc));
                    if (crc == packet_crc)
                    {
                        memcpy(packet, buffer, buffer_pos);
                        buffer_pos = 0;
                        state = WAIT_FOR_HEADER;
                        return 0;
                    }
                    else
                    {
                        log_message(LOG_ERROR, "CRC check failed: calculated %04x, expected %04x", crc, packet_crc);
                        buffer_pos = 0;
                        state = WAIT_FOR_HEADER;
                    }
                }
                break;
        }
    }
    return -EINVAL;
}

// 设置日志级别
static void set_log_level(log_level_t level)
{
    current_log_level = level;
}

// 初始化函数
void data_codec_init(data_codec_t *codec, log_level_t log_level, log_fn_t log_fn)
{
    codec->encode = encode_packet;
    codec->decode = decode_stream;
    codec->set_log_level = set_log_level;
    current_log_level = log_level;
    current_log_fn = log_fn;
    log_message(log_level, "Data Codec Version: %s\n", data_codec_get_version());
}

// 获取版本号
const char *data_codec_get_version(void)
{
    return DATA_CODEC_VERSION;
}
